1 /* 2 Copyright: Marcelo S. N. Mancini (Hipreme|MrcSnm), 2018 - 2021 3 License: [https://creativecommons.org/licenses/by/4.0/|CC BY-4.0 License]. 4 Authors: Marcelo S. N. Mancini 5 6 Copyright Marcelo S. N. Mancini 2018 - 2021. 7 Distributed under the CC BY-4.0 License. 8 (See accompanying file LICENSE.txt or copy at 9 https://creativecommons.org/licenses/by/4.0/ 10 */ 11 12 module hip.api.internal; 13 import hip.api; 14 import hip.util.lifetime; 15 16 ///Used for creating a function which will generate an overload to call a function pointer 17 struct Overload 18 { 19 string targetName; 20 } 21 22 version(WebAssembly) version = ErrorOnLoadSymbol; 23 version(PSVita) version = ErrorOnLoadSymbol; 24 25 version(ScriptAPI) version = LoadFunctionPointers; 26 27 28 version(LoadFunctionPointers) 29 { 30 __gshared void* _dll; 31 void initializeHip() 32 { 33 version(ErrorOnLoadSymbol) 34 { 35 assert(false, "Cannot load symbols in this version."); 36 } 37 else 38 { 39 version(Windows){_dll = GetModuleHandle(null);} 40 else 41 { 42 import core.sys.posix.dlfcn:dlopen, RTLD_NOW; 43 _dll = dlopen(null, RTLD_NOW); 44 } 45 import core.stdc.stdio; 46 if(_dll == null) 47 printf("Could not load GetModuleHandle(null)\n"); 48 hipDestroy = cast(typeof(hipDestroy))_loadSymbol(_dll, "hipDestroy"); 49 if(hipDestroy == null) 50 printf("Fatal error: could not load hipDestroy\n"); 51 } 52 } 53 } 54 version(Windows) 55 { 56 @nogc nothrow extern(Windows) 57 { 58 void* GetModuleHandleW(const(wchar)* str); 59 void* GetProcAddress(void* mod, const(char)* func); 60 void* FreeLibrary(void* lib); 61 uint GetLastError(); 62 } 63 alias GetModuleHandle = GetModuleHandleW; 64 alias _loadSymbol = GetProcAddress; 65 } 66 67 version(Posix) 68 { 69 import core.sys.posix.dlfcn:dlsym; 70 alias _loadSymbol = dlsym; 71 } 72 enum bool isFunctionPointer(alias T) = is(typeof(*T) == function); 73 74 /** 75 * Prefer using that function instead of loadSymbol, as compile 76 * time sequences reduced the binary size in almost 100kb. 77 * 78 * The problem is not yet solved, but it is a lot better than doing several 79 * template instantiations 80 */ 81 void loadSymbols(Ts...)() 82 { 83 static foreach(s; Ts) 84 s = cast(typeof(s))_loadSymbol(_dll, s.stringof); 85 } 86 87 /** 88 * This function will load all function pointers defined in the module passed. 89 */ 90 void loadModuleFunctionPointers(alias targetModule, string exportedClass = "")() 91 { 92 string prefix = ""; 93 string importedFunctionName; 94 static if(exportedClass != "") 95 prefix = exportedClass~"_"; 96 static foreach(member; __traits(allMembers, targetModule)) 97 {{ 98 alias f = __traits(getMember, targetModule, member); 99 static if(isFunctionPointer!(f)) 100 { 101 importedFunctionName = prefix~member~'\0'; 102 if(f is null) 103 { 104 f = cast(typeof(f))_loadSymbol(_dll, importedFunctionName.ptr); 105 if(f is null) 106 { 107 import core.stdc.stdio; 108 printf(f.stringof~" wasn't able to load (tried with %s)\n", importedFunctionName.ptr); 109 } 110 } 111 } 112 }} 113 } 114 115 116 string generateFunctionDefinitionFromFunctionPointer(alias funcPointerSymbol, string name)() 117 { 118 assert(__ctfe); 119 120 import std.traits; 121 string params; 122 string identifiers; 123 124 bool isFirst = true; 125 alias storage = ParameterStorageClassTuple!funcPointerSymbol; 126 static foreach(i, p; Parameters!funcPointerSymbol) 127 { 128 if(!isFirst) 129 { 130 params~= ","; 131 identifiers~= ","; 132 } 133 else 134 isFirst = false; 135 if(storage[i] != ParameterStorageClass.none) 136 params~= storage[i].stringof["ParameterStorageClass.".length..$-1] ~" "; //Remove enum namespace and the "_" 137 params~= p.stringof ~ " _"~i.stringof; 138 identifiers~= "_"~i.stringof; 139 } 140 141 return (ReturnType!funcPointerSymbol).stringof ~ " "~ name ~ "("~params 142 ~"){return "~ funcPointerSymbol.stringof ~ "("~identifiers ~ ");}"; 143 144 } 145 146 mixin template OverloadsForFunctionPointers(alias targetModule) 147 { 148 import std.traits; 149 static foreach(symbol; getSymbolsByUDA!(targetModule, Overload)) 150 { 151 pragma(msg, generateFunctionDefinitionFromFunctionPointer!(symbol, getUDAs!(symbol, Overload)[0].targetName)); 152 mixin(generateFunctionDefinitionFromFunctionPointer!(symbol, getUDAs!(symbol, Overload)[0].targetName)); 153 } 154 } 155 156 mixin template ExpandClassFunctionPointers(alias targetClass) 157 { 158 import hip.api.internal: isFunctionPointer; 159 160 static foreach(mem; __traits(allMembers, targetClass)) 161 { 162 static if(isFunctionPointer!(__traits(getMember, targetClass, mem))) 163 { 164 mixin(__traits(getVisibility, __traits(getMember, targetClass, mem)), " alias ", mem, " = ", __traits(identifier, targetClass), ".", mem,";"); 165 } 166 } 167 } 168 template Flag(string f) 169 { 170 enum Flag : bool 171 { 172 No = false, 173 Yes = true 174 } 175 } 176 177 alias UseExportedClass = Flag!"UseExportedClass"; 178 179 void loadClassFunctionPointers(alias targetClass, 180 UseExportedClass useExported = UseExportedClass.No, 181 string exportedClass = "") 182 () 183 { 184 string prefix = ""; 185 string importedFunctionName; 186 187 version(ErrorOnLoadSymbol) 188 { 189 assert(false, "Cannot load symbols in this version."); 190 } 191 else 192 { 193 string nExportedClass = exportedClass; 194 static if(useExported) 195 { 196 static if(exportedClass == "") 197 nExportedClass = targetClass.stringof; 198 prefix = nExportedClass~"_"; 199 } 200 static foreach(member; __traits(allMembers, targetClass)) 201 {{ 202 alias f = __traits(getMember, targetClass, member); 203 static if(isFunctionPointer!(f)) 204 { 205 importedFunctionName = prefix~member~'\0'; 206 f = cast(typeof(f))_loadSymbol(_dll, importedFunctionName.ptr); 207 if(f is null) 208 { 209 import core.stdc.stdio; 210 printf(f.stringof ~ " wasn't able to load (tried with %s)\n", importedFunctionName.ptr); 211 212 f = cast(typeof(f))() 213 { 214 printf("Symbol '"~member~"' wasn't able to load.\n"~ 215 "If on that is working on LDC, please check for exportd."~ 216 "referenceExported to see if that function referenced. Check https://github.com/dlang/dmd/issues/17582 for more information. \n\n\t"~ 217 "Hipreme Engine will exit.\n" 218 ); 219 assert(false); 220 }; 221 } 222 } 223 }} 224 } 225 } 226 227 template loadSymbolsFromExportD(string exportedClass, Ts...) 228 { 229 version(ErrorOnLoadSymbol) 230 { 231 enum impl = ""; 232 } 233 else 234 { 235 enum impl = () 236 { 237 assert(__ctfe); 238 239 enum e = '"'~exportedClass~"_\""; 240 string ret; 241 static foreach(i, s; Ts) 242 { 243 ret~= s.stringof ~"= cast(typeof("~s.stringof~ " ))_loadSymbol(_dll, ("~e~"~\""~s.stringof~"\\0\").ptr);"; 244 if(s.stringof is null) 245 { 246 import core.stdc.stdio; 247 printf("Could not load "~s.stringof~" (tried with "~ e~s.stringof~")\n"); 248 } 249 } 250 return ret; 251 }(); 252 } 253 254 enum loadSymbolsFromExportD = impl; 255 }